/**
 * 
 */
package de.tuhh.simsearch.model.persistence.usermgmt.eao;

import static org.junit.Assert.assertEquals;

import java.util.LinkedList;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;

import org.eclipse.persistence.config.CacheUsage;
import org.eclipse.persistence.config.QueryHints;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

/*
 import javax.persistence.EntityManagerFactory;
 import javax.persistence.Persistence;
 import javax.persistence.EntityManager;
 import javax.persistence.Query;

 *
 *hinzugefügt
 *
 */
import de.tuhh.simsearch.junit.Utilities;
import de.tuhh.simsearch.model.persistence.usermgmt.entities.GroupEntity;
import de.tuhh.simsearch.model.persistence.usermgmt.entities.PreferenceEntity;
import de.tuhh.simsearch.model.persistence.usermgmt.entities.UserEntity;

/**
 * @author sim-search
 * 
 */
public class UserMgmtEAOTest {

  private EntityManager em;
  private UserMgmtEAO eao;

  @BeforeClass
  public static void onlyOnceAtStart() {

    EntityManager entityman = Utilities.getEntityManager();
    UserMgmtEAO entityao = new UserMgmtEAO(entityman);

    entityman.getTransaction().begin();
    entityao.persistUser(new UserEntity("beta"));
    entityao.persistGroup(new GroupEntity("picturesfans"));

    // for the test changePassword

    String un = "Bernd";
    entityao.persistUser(new UserEntity(un));
    entityman.getTransaction().commit();

    TypedQuery<UserEntity> qUser = entityman.createQuery("SELECT u FROM UserEntity u WHERE u.name = :name",
        UserEntity.class).setParameter("name", un);
    UserEntity myUser = qUser.getSingleResult();

    entityman.getTransaction().begin();
    myUser.setPassword("mysecurepassword");
    entityman.getTransaction().commit();
  }

  @AfterClass
  public static void onlyOnceAtEnd() {

    // EntityManager entityman = Utilities.getEntityManager();
    // UserMgmtEAO entityao = new UserMgmtEAO(entityman);
  }

  @Before
  public void setUp() throws Exception {

    em = Utilities.getEntityManager();
    eao = new UserMgmtEAO(em);
  }

  /**
   * create 2 users without specified entries
   * 
   */

  /*
   * 
   * @Test public void testCreateUsers() { em.getTransaction().begin();  eao.createUsers(); Query q = em.createQuery("select u from UserEntity u");
   * assertTrue(q.getResultList().size() == 2); em.getTransaction().commit(); }
   */

  /**
   * create a new group whose name is "Musikfans"
   */

  @Test
  public void testGenerateGroup() {

    em.getTransaction().begin();

    eao.persistGroup(new GroupEntity("Musikfans"));
    em.getTransaction().commit();
  }

  /**
   * delete a group with the specified name
   */

  @Test
  public void deleteGroup() {

    em.getTransaction().begin();

    eao.deleteGroup("picturesfans");
    em.getTransaction().commit();
  }

  /**
   * test the creation of a user
   */

  @Test
  public void testCreateUser() {

    em.getTransaction().begin();

    eao.persistUser(new UserEntity("gamma"));
    em.getTransaction().commit();
  }

  /**
   * test the deletion of a user whose name is beta
   */

  @Test
  public void testDeleteUser() {

    em.getTransaction().begin();

    eao.deleteUser("beta");
    em.getTransaction().commit();
  }

  /**
   * adding a user to group - funktioniert, nachdem private die Variable members ist the ID tells which group the user
   * wants to join
   */

  @Test
  public void testAddUserToGroup() {

    em.getTransaction().begin();

    eao.persistGroup(new GroupEntity("notmusicfans"));
    UserEntity myUser = new UserEntity("funktioniert8?");
    // myUser.setAdministrator(true); // neu diese Zeile
    em.persist(myUser);
    // neu 13 11 13
    eao.addUserToGroup("funktioniert8?", "notmusicfans", false);

    // assertEquals("the user must be administrator", true, eao.isAdmin("funktioniert8?", 5L));

    // eao.addUserToGroup(user, groupID);
    em.getTransaction().commit();
  }

  /**
   * the name "musica" is already in use, so false is the expected return value
   * 
   * funktioniert
   * 
   */

  @Test
  public void testIsGroupNameFree() {

    em.getTransaction().begin();

    assertEquals("the group name musica is already used", false, eao.isGroupNameFree("Musikfans"));
    em.getTransaction().commit();
  }

  /**
   * the name "STS" is already in use, so false is the expected return value
   * 
   */

  @Test
  public void testIsUserNameFree() {

    em.getTransaction().begin();

    assertEquals("the user name myUser is already used", false, eao.isUserNameFree("Bob"));
    em.getTransaction().commit();
  }

  @Test
  public void testIsPreferenceNameFree() {

    em.getTransaction().begin();

    PreferenceEntity myPreference = new PreferenceEntity("History", 1);
    // myPreference.setContentID(2);

    em.persist(myPreference);

    em.getTransaction().commit();

    em.getTransaction().begin();

    assertEquals("the preference name History and the contentID 1 are already used", false,
        eao.isPreferenceNameFree("History", 1));
    em.getTransaction().commit();
  }

  /**
   * generate two users - one of them is administrator and the other one not
   * 
   */

  @Test
  public void testGenerateUser() {

    em.getTransaction().begin();

    UserEntity myUserAlice = new UserEntity("Alice");
    UserEntity myUserBob = new UserEntity("Bob");
    // myUserAlice.setAdministrator(true);
    // myUserBob.setAdministrator(false);

    eao.persistUser(myUserAlice);
    eao.persistUser(myUserBob);

    em.getTransaction().commit();
  }

  @Test
  public void testCreateGroup() {

    em.getTransaction().begin();

    GroupEntity myGroup = new GroupEntity("Rockgroup");
    // myUserAlice.setAdministrator(true);
    // myUserBob.setAdministrator(false);
    eao.persistGroup(myGroup);

    em.getTransaction().commit();
  }

  /**
   * first create a new preference and then add it to a specific group where a specific user is registered
   * 
   * macht dies Sinn, dass nur ein Nutzer eine neue Präferenz hat und die anderen aus der Gruppe nun nicht?
   */

  @Test
  public void testAddPreference() {

    em.getTransaction().begin();

    PreferenceEntity myPreference = new PreferenceEntity("Jazz", 2);
    // myPreference.setContentID(2);

    em.persist(myPreference);

    assertEquals("the preference name must be Jazz", "Jazz", eao.getPreferenceEntity("Jazz", 2).getName());

    assertEquals("Did add pref work?", true, eao.addPreference("Alice", "Jazz", 2));

    TypedQuery<PreferenceEntity> query = em
        .createQuery("SELECT u.preferences FROM UserEntity u WHERE u.name = :userName", PreferenceEntity.class)
        .setParameter("userName", "Alice").setHint(QueryHints.CACHE_USAGE, CacheUsage.DoNotCheckCache);

    System.out.println(query.getResultList());

    assertEquals("There should be one preference", 1, (query.getResultList().size()));
    assertEquals("The result should be Jazz", "Jazz", query.getSingleResult().getName());

    assertEquals("Did add pref work?", true, eao.addPreference("Bob", "Jazz", 2));

    /*
     * eao.removePreference("Alice", "Jazz");
     * 
     * System.out.println(query.getResultList()); assertEquals("There should be zero preference", true,
     * (query.getSingleResult() == null));
     */
    em.getTransaction().commit();
  }

  /*
   * the preference identified by its name ( später über die category ID identifizieren lassen ) has to be removed
   * 
   * funktioniert nicht - exception: Zeiger kann kein Element referenzieren, außer der 0, da diese zeile einen fehler
   * verursacht Iterator<UserEntity> iterator = myGroup.getMembers().iterator();
   * 
   */


  /*
    @Test
    public void testIsAdministrator() { em.getTransaction().begin(); 

      assertEquals("the user must be administrator", true, eao.isAdmin("funktioniert8?", "notmusicfans0"));

    em.getTransaction().commit(); }
  */
  @Test
  public void testIsUserInGroup() {

    em.getTransaction().begin();

    String un = "Anton";
    String gn = "Picturefans";
    eao.persistGroup(new GroupEntity(gn));
    eao.persistUser(new UserEntity(un));
    eao.addUserToGroup(un, gn, false);

    assertEquals("the user has to be in the group", true, eao.isUserInGroup("Anton", "Picturefans"));
    em.getTransaction().commit();
  }

  @Test
  public void testAddUserToGroup_2() {

    em.getTransaction().begin();

    eao.persistGroup(new GroupEntity("morePicturefans"));
    UserEntity myUser = new UserEntity("Sally");
    // hier eigentlich Methode aufrufen, um zu prüfen, ob jemand anderes bereits den gleichen Nutzernamen verwendet

    em.persist(myUser);

    assertEquals("Sally should be a pending user", true, eao.addUserToGroup("Sally", "morePicturefans", true));

    em.getTransaction().commit();
  }

  @Test
  public void testRemoveUserFromGroup() {

    em.getTransaction().begin();

    String un = "Alfons";
    String gn = "textfans";
    eao.persistGroup(new GroupEntity(gn));
    eao.persistUser(new UserEntity(un));
    // hier eigentlich Methode aufrufen, um zu prüfen, ob jemand anderes bereits den gleichen Nutzernamen verwendet
    eao.addUserToGroup(un, gn, true);
    assertEquals("Alfons should be removed from the group", true, eao.removeUserFromGroup(un, gn));
    em.getTransaction().commit();
  }

  @Test
  public void testChangePassword() {

    em.getTransaction().begin();

    assertEquals("Bernd's password was changed", true, eao.changePassword("Bernd", "sts"));

    em.getTransaction().commit();
  }

  @Test
  public void testGetGroupEntity() {

    em.getTransaction().begin();

    String gn = "nottextfans";
    eao.persistGroup(new GroupEntity(gn));

    assertEquals("name of the group is Picturefans", "nottextfans", eao.getGroupEntity(gn).getName());

    em.getTransaction().commit();
  }

  @Test
  public void testGetUserEntity() {

    em.getTransaction().begin();

    String un = "testUserName";
    eao.persistUser(new UserEntity(un));

    assertEquals("name of the user is testUserName", "testUserName", eao.getUserEntity(un).getName());

    em.getTransaction().commit();
  }

  @Test
  public void testApprovePendingUser() {

    em.getTransaction().begin();

    String un = "Sandra";
    String gn = "notPicturefans";

    eao.persistGroup(new GroupEntity(gn));
    UserEntity myUser = new UserEntity(un);
    // hier eigentlich Methode aufrufen, um zu prüfen, ob jemand anderes bereits den gleichen Nutzernamen verwendet

    em.persist(myUser);

    assertEquals("Sandra should be a pending user", true, eao.addUserToGroup(un, gn, true));

    assertEquals("Sandra is a member of the group", true, eao.addUserToGroup(un, gn, false));
    em.getTransaction().commit();
  }

  @Test
  public void testCheckPassword() {

    em.getTransaction().begin();

    assertEquals("Bernd's password is checked", true, eao.checkPassword("Bernd", "sts"));
    em.getTransaction().commit();
  }

  @Test
  public void testSearchInGroup() {

    em.getTransaction().begin();

    assertEquals("one group starts with 'pictures'", 2, eao.searchInGroups("text").size());
    // einer zu wenig wird gezählt - 6 obwohl es eigentlich 7 sein müssten - bei fans
    // bestimmt müsste man die tables ersteinmal droppen
    // text - 2
    em.getTransaction().commit();
  }

  @Test
  public void testSearchUserPreference() {

    em.getTransaction().begin();

    UserEntity myUserBerta = new UserEntity("Berta");

    eao.persistUser(myUserBerta);

    em.getTransaction().commit();

    em.getTransaction().begin();

    PreferenceEntity myPreference = new PreferenceEntity("Klassik", 2);
    // myPreference.setContentID(2);

    em.persist(myPreference);

    eao.addPreference("Berta", "Klassik", 2);

    assertEquals("Did add pref work?", true, eao.addPreference("Berta", "Klassik", 2));

    List<String> usersPreferences = new LinkedList<String>();

    usersPreferences = eao.searchUserPreferences("Berta");

    for (String c : usersPreferences) {
      System.out.println(c);
    }
    /*
     * eao.removePreference("Alice", "Jazz");
     * 
     * System.out.println(query.getResultList()); assertEquals("There should be zero preference", true,
     * (query.getSingleResult() == null));
     */
    em.getTransaction().commit();
  }

  @Test
  public void testPersistPreference() {

    em.getTransaction().begin();

    PreferenceEntity myPreference = new PreferenceEntity("notRock", 2);
    // myPreference.setContentID(2);

    em.persist(myPreference);

    em.getTransaction().commit();

    assertEquals("the preference name notRock and the contentID 2 are already used", false,
        eao.isPreferenceNameFree("notRock", 2));

    assertEquals("the preference name must be notRock", "notRock", eao.getPreferenceEntity("notRock", 2).getName());

  }
}
// http://localhost:8080/SimilaritySearchWEB/

// vor dem grant use simsearchusermgmt eingeben

// user name darf nicht doppelt sein - da ja nun primary key

// getter und setter für das password feld